home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1991, 1996, 1997 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* gxclist.c */
- /* Command list writing for Ghostscript. */
- #include "memory_.h"
- #include "gx.h"
- #include "gp.h"
- #include "gpcheck.h"
- #include "gserrors.h"
- #include "gxdevice.h"
- #include "gxdevmem.h" /* must precede gxcldev.h */
- #include "gxcldev.h"
-
- #define cdev cwdev
-
- /* Forward declarations of procedures */
- private dev_proc_open_device(clist_open);
- private dev_proc_output_page(clist_output_page);
- private dev_proc_open_device(clist_close);
- private dev_proc_get_band(clist_get_band);
- /* In gxclrect.c */
- extern dev_proc_fill_rectangle(clist_fill_rectangle);
- extern dev_proc_copy_mono(clist_copy_mono);
- extern dev_proc_copy_color(clist_copy_color);
- extern dev_proc_copy_alpha(clist_copy_alpha);
- extern dev_proc_strip_tile_rectangle(clist_strip_tile_rectangle);
- extern dev_proc_strip_copy_rop(clist_strip_copy_rop);
- /* In gxclread.c */
- extern dev_proc_get_bits(clist_get_bits);
-
- /* The device procedures */
- gx_device_procs gs_clist_device_procs =
- { clist_open,
- gx_forward_get_initial_matrix,
- gx_default_sync_output,
- clist_output_page,
- clist_close,
- gx_forward_map_rgb_color,
- gx_forward_map_color_rgb,
- clist_fill_rectangle,
- gx_default_tile_rectangle,
- clist_copy_mono,
- clist_copy_color,
- gx_default_draw_line,
- clist_get_bits,
- gx_forward_get_params,
- gx_forward_put_params,
- gx_forward_map_cmyk_color,
- gx_forward_get_xfont_procs,
- gx_forward_get_xfont_device,
- gx_forward_map_rgb_alpha_color,
- gx_forward_get_page_device,
- gx_forward_get_alpha_bits,
- clist_copy_alpha,
- clist_get_band,
- gx_default_copy_rop,
- gx_default_fill_path,
- gx_default_stroke_path,
- gx_default_fill_mask,
- gx_default_fill_trapezoid,
- gx_default_fill_parallelogram,
- gx_default_fill_triangle,
- gx_default_draw_thin_line,
- gx_default_begin_image,
- gx_default_image_data,
- gx_default_end_image,
- clist_strip_tile_rectangle,
- clist_strip_copy_rop,
- gx_forward_get_clipping_box
- };
-
- /* ------ Define the command set and syntax ------ */
-
- /* Define the clipping enable/disable opcodes. */
- /* The path extensions initialize these to their proper values. */
- byte cmd_opvar_disable_clip = 0xff;
- byte cmd_opvar_enable_clip = 0xff;
-
- #ifdef DEBUG
- const char *cmd_op_names[16] = { cmd_op_name_strings };
- private const char *cmd_misc_op_names[16] = { cmd_misc_op_name_strings };
- const char **cmd_sub_op_names[16] =
- { cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- };
- private ulong far_data cmd_op_counts[256];
- private ulong far_data cmd_op_sizes[256];
- private ulong cmd_tile_reset, cmd_tile_found, cmd_tile_added;
- extern ulong cmd_diffs[5]; /* in gxclpath.c */
- private ulong cmd_same_band, cmd_other_band;
- int
- cmd_count_op(int op, uint size)
- { cmd_op_counts[op]++;
- cmd_op_sizes[op] += size;
- if ( gs_debug_c('L') )
- { const char **sub = cmd_sub_op_names[op >> 4];
- if ( sub )
- dprintf2(", %s(%u)\n", sub[op & 0xf], size);
- else
- dprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf, size);
- fflush(dstderr);
- }
- return op;
- }
- void
- cmd_uncount_op(int op, uint size)
- { cmd_op_counts[op]--;
- cmd_op_sizes[op] -= size;
- }
- #endif
-
- /* Initialization for imager state. */
- /* The initial scale is arbitrary. */
- const gs_imager_state clist_imager_state_initial =
- { gs_imager_state_initial(300.0 / 72.0) };
-
- /*
- * The buffer area (data, data_size) holds a bitmap cache when both writing
- * and reading. The rest of the space is used for the command buffer and
- * band state bookkeeping when writing, and for the rendering buffer (image
- * device) when reading. For the moment, we divide the space up
- * arbitrarily, except that we allocate less space for the bitmap cache if
- * the device doesn't need halftoning.
- *
- * All the routines for allocating tables in the buffer are idempotent, so
- * they can be used to check whether a given-size buffer is large enough.
- */
-
- /*
- * Calculate the desired size for the tile cache.
- */
- private uint
- clist_tile_cache_size(const gx_device *target, uint data_size)
- { uint bits_size =
- (data_size / 5) & -align_cached_bits_mod; /* arbitrary */
-
- if ( (gx_device_has_color(target) ? target->color_info.max_color :
- target->color_info.max_gray) >= 31
- )
- { /* No halftones -- cache holds only Patterns & characters. */
- bits_size -= bits_size >> 2;
- }
- #define min_bits_size 1024
- if ( bits_size < min_bits_size )
- bits_size = min_bits_size;
- #undef min_bits_size
- return bits_size;
- }
-
- /*
- * Initialize the allocation for the tile cache. Sets: tile_hash_mask,
- * tile_max_count, tile_table, chunk (structure), bits (structure).
- */
- private int
- clist_init_tile_cache(gx_device *dev, byte *init_data, ulong data_size)
- { byte *data = init_data;
- uint bits_size = data_size;
- /*
- * Partition the bits area between the hash table and the actual
- * bitmaps. The per-bitmap overhead is about 24 bytes; if the
- * average character size is 10 points, its bitmap takes about 24 +
- * 0.5 * 10/72 * xdpi * 10/72 * ydpi / 8 bytes (the 0.5 being a
- * fudge factor to account for characters being narrower than they
- * are tall), which gives us a guideline for the size of the hash
- * table.
- */
- uint avg_char_size =
- (uint)(dev->x_pixels_per_inch * dev->y_pixels_per_inch *
- (0.5 * 10/72 * 10/72 / 8)) + 24;
- uint hc = bits_size / avg_char_size;
- uint hsize;
-
- while ( (hc + 1) & hc )
- hc |= hc >> 1; /* make mask (power of 2 - 1) */
- if ( hc < 0xff )
- hc = 0xff; /* make allowance for halftone tiles */
- else if ( hc > 0xfff )
- hc = 0xfff; /* cmd_op_set_tile_index has 12-bit operand */
- /* Make sure the tables will fit. */
- while ( hc >= 3 && (hsize = (hc + 1) * sizeof(tile_hash)) >= bits_size )
- hc >>= 1;
- if ( hc < 3 )
- return_error(gs_error_rangecheck);
- cdev->tile_hash_mask = hc;
- cdev->tile_max_count = hc - (hc >> 2);
- cdev->tile_table = (tile_hash *)data;
- data += hsize;
- bits_size -= hsize;
- gx_bits_cache_chunk_init(&cdev->chunk, data, bits_size);
- gx_bits_cache_init(&cdev->bits, &cdev->chunk);
- return 0;
- }
-
- /*
- * Initialize the allocation for the bands. Requires: target. Sets:
- * page_band_height (=page_info.band_params.BandHeight), nbands.
- */
- private int
- clist_init_bands(gx_device *dev, uint data_size, int band_width,
- int band_height)
- { gx_device *target = cdev->target;
- int nbands;
-
- if ( gdev_mem_data_size((gx_device_memory *)target, band_width,
- band_height) > data_size
- )
- return_error(gs_error_rangecheck);
- cdev->page_band_height = band_height;
- nbands = (target->height + band_height - 1) / band_height;
- cdev->nbands = nbands;
- #ifdef DEBUG
- if ( gs_debug_c('l') | gs_debug_c(':') )
- dprintf4("[l]width=%d, band_width=%d, band_height=%d, nbands=%d\n",
- target->width, band_width, band_height, nbands);
- #endif
- return 0;
- }
-
- /*
- * Initialize the allocation for the band states, which are used only
- * when writing. Requires: nbands. Sets: states, cbuf, cend.
- */
- private int
- clist_init_states(gx_device *dev, byte *init_data, uint data_size)
- { ulong state_size = cdev->nbands * (ulong)sizeof(gx_clist_state);
-
- /*
- * The +100 in the next line is bogus, but we don't know what the
- * real check should be.
- */
- if ( state_size + sizeof(cmd_prefix) + cmd_largest_size + 100 > data_size )
- return_error(gs_error_rangecheck);
- cdev->states = (gx_clist_state *)init_data;
- cdev->cbuf = init_data + state_size;
- cdev->cend = init_data + data_size;
- return 0;
- }
-
- /*
- * Initialize all the data allocations. Requires: target. Sets:
- * page_tile_cache_size, page_info.band_params.BandWidth,
- * page_info.band_params.BandBufferSpace, + see above.
- */
- private int
- clist_init_data(gx_device *dev, byte *init_data, uint data_size)
- { gx_device *target = cdev->target;
- const int band_width =
- cdev->page_info.band_params.BandWidth =
- (cdev->band_params.BandWidth ? cdev->band_params.BandWidth :
- target->width);
- int band_height = cdev->band_params.BandHeight;
- const uint band_space =
- cdev->page_info.band_params.BandBufferSpace =
- (cdev->band_params.BandBufferSpace ?
- cdev->band_params.BandBufferSpace : data_size);
- byte *data = init_data;
- uint size = band_space;
- uint bits_size;
- int code;
-
- if ( band_height )
- { /*
- * The band height is fixed, so the band buffer requirement
- * is completely determined.
- */
- uint band_data_size =
- gdev_mem_data_size((gx_device_memory *)target,
- band_width, band_height);
-
- if ( band_data_size >= band_space )
- return_error(gs_error_rangecheck);
- bits_size = min(band_space - band_data_size, data_size >> 1);
- }
- else
- { /*
- * Choose the largest band height that will fit in the
- * rendering-time buffer.
- */
- bits_size = clist_tile_cache_size(target, band_space);
- bits_size = min(bits_size, data_size >> 1);
- band_height = gdev_mem_max_height((gx_device_memory *)target,
- band_width,
- band_space - bits_size);
- if ( band_height == 0 )
- return_error(gs_error_rangecheck);
- }
- code = clist_init_tile_cache(dev, data, bits_size);
- if ( code < 0 )
- return code;
- cdev->page_tile_cache_size = bits_size;
- data += bits_size;
- size -= bits_size;
- code = clist_init_bands(dev, size, band_width, band_height);
- if ( code < 0 )
- return code;
- return clist_init_states(dev, data, data_size - bits_size);
- }
- /*
- * Initialize the device state (for writing). This routine requires only
- * data, data_size, and target to be set, and is idempotent.
- */
- private int
- clist_init(gx_device *dev)
- { int code = clist_init_data(dev, cdev->data, cdev->data_size);
- int nbands = cdev->nbands;
-
- if ( code < 0 )
- return code;
- /* Now initialize the rest of the state. */
- cdev->ymin = cdev->ymax = -1; /* render_init not done yet */
- memset(cdev->tile_table, 0, (cdev->tile_hash_mask + 1) *
- sizeof(*cdev->tile_table));
- cdev->cnext = cdev->cbuf;
- cdev->ccl = 0;
- cdev->band_range_list.head = cdev->band_range_list.tail = 0;
- cdev->band_range_min = 0;
- cdev->band_range_max = nbands - 1;
- { int band;
- gx_clist_state *states = cdev->states;
-
- for ( band = 0; band < nbands; band++, states++ )
- { static const gx_clist_state cls_initial =
- { cls_initial_values };
- *states = cls_initial;
- }
- }
- /*
- * Round up the size of the per-tile band mask so that the bits,
- * which follow it, stay aligned.
- */
- cdev->tile_band_mask_size =
- ((nbands + (align_bitmap_mod * 8 - 1)) >> 3) &
- ~(align_bitmap_mod - 1);
- /*
- * Initialize the all-band parameters to impossible values,
- * to force them to be written the first time they are used.
- */
- memset(&cdev->tile_params, 0, sizeof(cdev->tile_params));
- cdev->tile_depth = 0;
- cdev->tile_known_min = nbands;
- cdev->tile_known_max = -1;
- cdev->imager_state = clist_imager_state_initial;
- cdev->clip_path = NULL;
- cdev->clip_path_id = gs_no_id;
- cdev->color_space = 0;
- { int i;
- for ( i = 0; i < countof(cdev->transfer_ids); ++i )
- cdev->transfer_ids[i] = gs_no_id;
- }
- cdev->black_generation_id = gs_no_id;
- cdev->undercolor_removal_id = gs_no_id;
- cdev->device_halftone_id = gs_no_id;
- cdev->in_image = false;
- return 0;
- }
- /* Open the device by initializing the device state and opening the */
- /* scratch files. */
- private int
- clist_open(gx_device *dev)
- { char fmode[4];
- int code;
-
- cdev->page_cfile = 0; /* in case of failure */
- cdev->page_bfile = 0; /* ditto */
- code = clist_init(dev);
- if ( code < 0 )
- return code;
- strcpy(fmode, "w+");
- strcat(fmode, gp_fmode_binary_suffix);
- cdev->page_cfname[0] = 0; /* create a new file */
- cdev->page_bfname[0] = 0; /* ditto */
- cdev->page_bfile_end_pos = 0;
- if ( (code = clist_fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
- &gs_memory_default, true)) < 0 ||
- (code = clist_fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
- &gs_memory_default, true)) < 0
- )
- clist_close(dev);
- return code;
- }
-
- /* The output_page procedure should never be called! */
- private int
- clist_output_page(gx_device *dev, int num_copies, int flush)
- { return_error(gs_error_Fatal);
- }
-
- /* Reset (or prepare to append to) the command list after printing a page. */
- int
- clist_finish_page(gx_device *dev, bool flush)
- { if ( flush )
- { clist_rewind(cdev->page_cfile, true, cdev->page_cfname);
- clist_rewind(cdev->page_bfile, true, cdev->page_bfname);
- cdev->page_bfile_end_pos = 0;
- }
- else
- { clist_fseek(cdev->page_cfile, 0L, SEEK_END, cdev->page_cfname);
- clist_fseek(cdev->page_bfile, 0L, SEEK_END, cdev->page_bfname);
- }
- return clist_init(dev); /* reinitialize */
- }
-
- /* Close the device by freeing the temporary files. */
- /* Note that this does not deallocate the buffer. */
- private int
- clist_close(gx_device *dev)
- { if ( cdev->page_cfile != NULL )
- { clist_fclose(cdev->page_cfile, cdev->page_cfname, true);
- cdev->page_cfile = NULL;
- }
- if ( cdev->page_bfile != NULL )
- { clist_fclose(cdev->page_bfile, cdev->page_bfname, true);
- cdev->page_bfile = NULL;
- }
- return 0;
- }
-
- /* Print statistics. */
- #ifdef DEBUG
- void
- cmd_print_stats(void)
- { int ci, cj;
- dprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
- cmd_tile_reset, cmd_tile_found, cmd_tile_added);
- dprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
- cmd_diffs[0], cmd_diffs[1], cmd_diffs[2], cmd_diffs[3],
- cmd_diffs[4]);
- dprintf2(" same_band = %lu, other_band = %lu\n",
- cmd_same_band, cmd_other_band);
- for ( ci = 0; ci < 0x100; ci += 0x10 )
- { const char **sub = cmd_sub_op_names[ci >> 4];
- if ( sub != 0 )
- { dprintf1("[l] %s =", cmd_op_names[ci >> 4]);
- for ( cj = ci; cj < ci + 0x10; cj += 2 )
- dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
- sub[cj-ci],
- cmd_op_counts[cj], cmd_op_sizes[cj],
- sub[cj-ci+1],
- cmd_op_counts[cj+1], cmd_op_sizes[cj+1]);
- }
- else
- { ulong tcounts = 0, tsizes = 0;
- for ( cj = ci; cj < ci + 0x10; cj++ )
- tcounts += cmd_op_counts[cj],
- tsizes += cmd_op_sizes[cj];
- dprintf3("[l] %s (%lu,%lu) =\n\t",
- cmd_op_names[ci >> 4], tcounts, tsizes);
- for ( cj = ci; cj < ci + 0x10; cj++ )
- if ( cmd_op_counts[cj] == 0 )
- dputs(" -");
- else
- dprintf2(" %lu(%lu)", cmd_op_counts[cj],
- cmd_op_sizes[cj]);
- }
- dputs("\n");
- }
- }
- #endif /* DEBUG */
-
- /* ------ Writing ------ */
-
- /* Utilities */
-
- /* Write the commands for one band or band range. */
- private int
- cmd_write_band(gx_device_clist_writer *cldev, int band_min, int band_max,
- cmd_list *pcl, byte cmd_end)
- { const cmd_prefix *cp = pcl->head;
-
- if ( cp != 0 || cmd_end != cmd_opv_end_run ) {
- clist_file_ptr cfile = cldev->page_cfile;
- clist_file_ptr bfile = cldev->page_bfile;
- cmd_block cb;
- byte end = cmd_count_op(cmd_end, 1);
- int code;
-
- cb.band_min = band_min;
- cb.band_max = band_max;
- cb.pos = clist_ftell(cfile);
- if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
- band_min, band_max, cb.pos);
- clist_fwrite_chars(&cb, sizeof(cb), bfile);
- if ( cp != 0 ) {
- pcl->tail->next = 0; /* terminate the list */
- for ( ; cp != 0; cp = cp->next ) {
- #ifdef DEBUG
- if ( (const byte *)cp < cldev->cbuf ||
- (const byte *)cp >= cldev->cend ||
- cp->size > cldev->cend - (const byte *)cp
- ) {
- lprintf1("cmd_write_band error at 0x%lx\n", (ulong)cp);
- return_error(gs_error_Fatal);
- }
- #endif
- clist_fwrite_chars(cp + 1, cp->size, cfile);
- }
- pcl->head = pcl->tail = 0;
- }
-
- clist_fwrite_chars(&end, 1, cfile);
- process_interrupts();
- if ( (code = clist_ferror_code(bfile)) < 0 ||
- (code = clist_ferror_code(cfile)) < 0
- )
- return_error(code);
- }
- return 0;
- }
-
- /* Write out the buffered commands, and reset the buffer. */
- private int
- cmd_write_buffer(gx_device_clist_writer *cldev, byte cmd_end)
- { int nbands = cldev->nbands;
- gx_clist_state *pcls;
- int band;
- int code = cmd_write_band(cldev, cldev->band_range_min,
- cldev->band_range_max,
- &cldev->band_range_list, cmd_opv_end_run);
-
- for ( band = 0, pcls = cldev->states;
- code >= 0 && band < nbands; band++, pcls++
- )
- code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
- cldev->cnext = cldev->cbuf;
- cldev->ccl = 0;
- cldev->band_range_list.head = cldev->band_range_list.tail = 0;
- #ifdef DEBUG
- if ( gs_debug_c('l') )
- cmd_print_stats();
- #endif
- return_check_interrupt(code);
- }
- /* End a page by flushing the buffer and terminating the command list. */
- int
- clist_end_page(gx_device_clist_writer *cldev)
- { int code = cmd_write_buffer(cldev, cmd_opv_end_page);
- cmd_block cb;
-
- if ( code < 0 )
- return code;
- /* Write the terminating entry in the block file. */
- /* Note that because of copypage, there may be many such entries. */
- cb.band_min = cb.band_max = cmd_band_end;
- cb.pos = clist_ftell(cldev->page_cfile);
- clist_fwrite_chars(&cb, sizeof(cb), cldev->page_bfile);
- cldev->page_bfile_end_pos = clist_ftell(cldev->page_bfile);
- #ifdef DEBUG
- if ( gs_debug_c('l') | gs_debug_c(':') )
- dprintf2("[l]clist_render_init at cfile=%ld, bfile=%ld\n",
- cb.pos, cldev->page_bfile_end_pos);
- #endif
- return 0;
- }
-
- /* Add a command to the appropriate band list, */
- /* and allocate space for its data. */
- /* Return the pointer to the data area. */
- /* If an error occurs, set cldev->error_code and return 0. */
- #define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
- byte *
- cmd_put_list_op(gx_device_clist_writer *cldev, cmd_list *pcl, uint size)
- { byte *dp = cldev->cnext;
- if ( size + cmd_headroom > cldev->cend - dp )
- { int code = cldev->error_code =
- cmd_write_buffer(cldev, cmd_opv_end_run);
- if ( code < 0 )
- return 0;
- return cmd_put_list_op(cldev, pcl, size);
- }
- if ( cldev->ccl == pcl )
- { /* We're adding another command for the same band. */
- /* Tack it onto the end of the previous one. */
- cmd_count_add1(cmd_same_band);
- #ifdef DEBUG
- if ( pcl->tail->size > dp - (byte *)(pcl->tail + 1) )
- { lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong)pcl->tail);
- }
- #endif
- pcl->tail->size += size;
- }
- else
- { /* Skip to an appropriate alignment boundary. */
- /* (We assume the command buffer itself is aligned.) */
- cmd_prefix *cp =
- (cmd_prefix *)(dp +
- ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
- cmd_count_add1(cmd_other_band);
- dp = (byte *)(cp + 1);
- if ( pcl->tail != 0 )
- {
- #ifdef DEBUG
- if ( pcl->tail < pcl->head ||
- pcl->tail->size > dp - (byte *)(pcl->tail + 1)
- )
- { lprintf1("cmd_put_list_op error at 0x%lx\n",
- (ulong)pcl->tail);
- }
- #endif
- pcl->tail->next = cp;
- }
- else
- pcl->head = cp;
- pcl->tail = cp;
- cldev->ccl = pcl;
- cp->size = size;
- }
- cldev->cnext = dp + size;
- return dp;
- }
- #ifdef DEBUG
- byte *
- cmd_put_op(gx_device_clist_writer *cldev, gx_clist_state *pcls, uint size)
- { if_debug3('L', "[L]band %d: size=%u, left=%u",
- (int)(pcls - cldev->states),
- size, (uint)(cldev->cend - cldev->cnext));
- return cmd_put_list_op(cldev, &pcls->list, size);
- }
- #endif
-
- /* Add a command for a range of bands. */
- byte *
- cmd_put_range_op(gx_device_clist_writer *cldev, int band_min, int band_max,
- uint size)
- { cmd_prefix *tail;
- if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
- band_min, band_max, size,
- (uint)(cldev->cend - cldev->cnext));
- if ( cldev->band_range_list.head == 0 ||
- band_min != cldev->band_range_min ||
- band_max != cldev->band_range_max ||
- (tail = cldev->band_range_list.tail,
- cldev->cnext != (byte *)(tail + 1) + tail->size)
- )
- { if ( (cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) < 0 )
- return 0;
- cldev->band_range_min = band_min;
- cldev->band_range_max = band_max;
- }
- return cmd_put_list_op(cldev, &cldev->band_range_list, size);
- }
-
- /* Write a variable-size positive integer. */
- int
- cmd_size_w(register uint w)
- { register int size = 1;
- while ( w > 0x7f ) w >>= 7, size++;
- return size;
- }
- byte *
- cmd_put_w(register uint w, register byte *dp)
- { while ( w > 0x7f ) *dp++ = w | 0x80, w >>= 7;
- *dp = w;
- return dp + 1;
- }
-
- /* Define the encodings of the different settable colors. */
- const clist_select_color_t
- clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
- clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
- clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
- clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
- int
- cmd_put_color(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- const clist_select_color_t *select,
- gx_color_index color, gx_color_index *pcolor)
- { byte *dp;
- long diff = (long)color - (long)(*pcolor);
- byte op, op_delta2;
-
- if ( diff == 0 )
- return 0;
- if ( select->tile_color )
- set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
- op = select->set_op;
- op_delta2 = select->delta2_op;
- if ( color == gx_no_color_index )
- { /*
- * We must handle this specially, because it may take more
- * bytes than the color depth.
- */
- set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
- }
- else
- { long delta;
- byte operand;
-
- switch ( (cldev->color_info.depth + 15) >> 3 )
- {
- case 5:
- if ( !((delta = diff + cmd_delta1_32_bias) &
- ~cmd_delta1_32_mask) &&
- (operand =
- (byte)((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
- operand != 15
- )
- { set_cmd_put_op(dp, cldev, pcls,
- (byte)(op + operand), 2);
- dp[1] = (byte)(((delta >> 10) & 0300) +
- (delta >> 5) + delta);
- break;
- }
- if ( !((delta = diff + cmd_delta2_32_bias) &
- ~cmd_delta2_32_mask)
- )
- { set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
- dp[1] = (byte)((delta >> 20) + (delta >> 16));
- dp[2] = (byte)((delta >> 4) + delta);
- break;
- }
- set_cmd_put_op(dp, cldev, pcls, op, 5);
- *++dp = (byte)(color >> 24);
- goto b3;
- case 4:
- if ( !((delta = diff + cmd_delta1_24_bias) &
- ~cmd_delta1_24_mask) &&
- (operand = (byte)(delta >> 16)) != 0 &&
- operand != 15
- )
- { set_cmd_put_op(dp, cldev, pcls,
- (byte)(op + operand), 2);
- dp[1] = (byte)((delta >> 4) + delta);
- break;
- }
- if ( !((delta = diff + cmd_delta2_24_bias) &
- ~cmd_delta2_24_mask)
- )
- { set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
- dp[1] = ((byte)(delta >> 13) & 0xf8) +
- ((byte)(delta >> 11) & 7);
- dp[2] = (byte)(((delta >> 3) & 0xe0) + delta);
- break;
- }
- set_cmd_put_op(dp, cldev, pcls, op, 4);
- b3: *++dp = (byte)(color >> 16);
- goto b2;
- case 3:
- set_cmd_put_op(dp, cldev, pcls, op, 3);
- b2: *++dp = (byte)(color >> 8);
- goto b1;
- case 2:
- if ( diff >= -7 && diff < 7 )
- { set_cmd_put_op(dp, cldev, pcls,
- op + (int)diff + 8, 1);
- break;
- }
- set_cmd_put_op(dp, cldev, pcls, op, 2);
- b1: dp[1] = (byte)color;
- }
- }
- *pcolor = color;
- return 0;
- }
-
- /* Put out a command to set the tile colors. */
- int
- cmd_set_tile_colors(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- gx_color_index color0, gx_color_index color1)
- { if ( color0 != pcls->tile_colors[0] )
- { int code = cmd_put_color(cldev, pcls,
- &clist_select_tile_color0,
- color0, &pcls->tile_colors[0]);
- if ( code < 0 )
- return code;
- }
- if ( color1 != pcls->tile_colors[1] )
- { int code = cmd_put_color(cldev, pcls,
- &clist_select_tile_color1,
- color1, &pcls->tile_colors[1]);
- if ( code < 0 )
- return code;
- }
- return 0;
- }
-
- /* Put out a command to set the tile phase. */
- int
- cmd_set_tile_phase(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- int px, int py)
- { int pcsize;
- byte *dp;
-
- pcls->tile_phase.x = px;
- pcls->tile_phase.y = py;
- pcsize = 1 + cmd_sizexy(pcls->tile_phase);
- set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
- ++dp;
- cmd_putxy(pcls->tile_phase, dp);
- return 0;
- }
-
- /* Write a command to enable or disable the logical operation. */
- int
- cmd_put_enable_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- int enable)
- { byte *dp;
- set_cmd_put_op(dp, cldev, pcls,
- (byte)(enable ? cmd_opv_enable_lop :
- cmd_opv_disable_lop),
- 1);
- pcls->lop_enabled = enable;
- return 0;
- }
-
- /* Write a command to enable or disable clipping. */
- /* This routine is only called if the path extensions are included. */
- int
- cmd_put_enable_clip(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- int enable)
- { byte *dp;
- set_cmd_put_op(dp, cldev, pcls,
- (byte)(enable ? cmd_opvar_enable_clip :
- cmd_opvar_disable_clip),
- 1);
- pcls->clip_enabled = enable;
- return 0;
- }
-
- /* Write a command to set the logical operation. */
- int
- cmd_set_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- gs_logical_operation_t lop)
- { byte *dp;
- uint lop_msb = lop >> 6;
-
- set_cmd_put_op(dp, cldev, pcls,
- cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
- dp[1] = cmd_set_misc_lop + (lop & 0x3f);
- cmd_put_w(lop_msb, dp + 2);
- pcls->lop = lop;
- return 0;
- }
-
- /* ---------------- Driver interface ---------------- */
-
- private int
- clist_get_band(gx_device *dev, int y, int *band_start)
- { int band_height = cdev->page_band_height;
- int start;
-
- if ( y < 0 )
- y = 0;
- else if ( y >= dev->height )
- y = dev->height;
- *band_start = start = y - y % band_height;
- return min(dev->height - start, band_height);
- }
-